package pl.edu.mimuw.mas.editor.widget;

import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Scale;

/**
 * Implementacja "suwaka" dla wartości typu float. Ponieważ jest to podklasa
 * Scale, która działa wyłącznie na intach, przy wołaniu metod getSelection,
 * setSelection, getMaximum, setMaximum, getMinimum, setMinimum podnoszony jest
 * wyjątek UnsupportedOperationException. Powyższe metody mogą być wołany tylko
 * przez inne metody tej klasy. Jest to sprawdzane w metodzie isLocalCall().
 */
public class FloatScale extends Scale {

	private static final float DEFUALT_MIN = -10f;
	private static final float DEFUALT_MAX = 10f;

	private static final int INTEGER_MAX = Integer.MAX_VALUE;
	
	private float min;
	private float max;

	public FloatScale(Composite arg0, int arg1) {
		super(arg0, arg1);
		super.setMaximum(INTEGER_MAX);
		super.setMinimum(0);
		min = DEFUALT_MIN;
		max = DEFUALT_MAX;
	}

	public float getFloatSelection() {
		int s = super.getSelection();
		float d = max - min;
		return min + d * s / INTEGER_MAX;
	}

	public void setFloatSelection(float arg) {
		if (arg < min || arg > max) {
			return;
		}
		
		float d = max - min;
		super.setSelection((int) ((arg - min) * INTEGER_MAX / d));
	}

	public float getFloatMaximum() {
		return max;
	}

	public void setFloatMaximum(float arg) {
		max = arg;
	}

	public float getFloatMinimum() {
		return min;
	}

	public void setFloatMinimum(float arg) {
		min = arg;
	}

	@Override
	public int getSelection() {
		if (!isLocalCall()) {
			throw new UnsupportedOperationException("This operation is not "
					+ "supported for FloatScale. Use getFloatSelection()");
		}
		return super.getSelection();
	}

	@Override
	public void setSelection(int arg) {
		throw new UnsupportedOperationException("This operation is not "
				+ "supported for FloatScale. Use setFloatSelection()");
	}

	@Override
	public int getMaximum() {
		if (!isLocalCall()) {
			throw new UnsupportedOperationException("This operation is not "
					+ "supported for FloatScale. Use getFloatMaximum()");
		}
		return super.getMaximum();
	}

	@Override
	public void setMaximum(int arg) {
		throw new UnsupportedOperationException("This operation is not "
				+ "supported for FloatScale. Use setFloatMaximum()");
	}

	@Override
	public int getMinimum() {
		if (!isLocalCall()) {
			throw new UnsupportedOperationException("This operation is not "
					+ "supported for FloatScale. Use getFloatMinimum()");
		}
		return super.getMinimum();
	}

	@Override
	public void setMinimum(int arg) {
		throw new UnsupportedOperationException("This operation is not "
				+ "supported for FloatScale. Use setFloatMinimum()");
	}

	@Override
	protected void checkSubclass() {
	}

	// It is possible that this method does not work
	// perfectly correct.
	private boolean isLocalCall() {
		Throwable t = new Throwable();
		StackTraceElement[] elements = t.getStackTrace();
		// I need elements[2] in order to get info
		// about object that called method which is
		// checking caller
		if (elements[2].getClassName().equals(Scale.class.getName())) {
			return true;
		}
		return false;
	}

}
